package com.sz.virtualbank.web.controller.user;

import com.sz.virtualbank.common.annotation.LoginRequired;
import com.sz.virtualbank.common.constant.CommonConstants;
import com.sz.virtualbank.common.result.CommonResponse;
import com.sz.virtualbank.common.utils.CheckUtil;
import com.sz.virtualbank.dao.entity.User;
import com.sz.virtualbank.service.user.UserService;
import com.sz.virtualbank.web.vo.user.LoginReqVO;
import com.sz.virtualbank.web.vo.user.RegisterReqVO;
import com.sz.virtualbank.web.vo.user.UserVO;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.Objects;

/**
 * 用户控制器
 *
 * @author Claude
 */
@Slf4j
@RestController
@RequestMapping("/api/user")
@Api(tags = "用户接口")
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping("/register")
    @ApiOperation("用户注册")
    public CommonResponse<UserVO> register(@RequestBody @Valid RegisterReqVO registerReq,
                                           HttpServletResponse response) {
        // 密码一致性校验
        CheckUtil.Biz.INSTANCE.isTrue(
                Objects.equals(registerReq.getPassword(), registerReq.getConfirmPassword()),
                "两次输入的密码不一致"
        );

        // 调用注册服务
        String token = userService.register(
                registerReq.getUsername(),
                registerReq.getPassword(),
                registerReq.getPhone(),
                registerReq.getValidCode()
        );

        // 设置Cookie
        setCookie(response, token);

        // 获取用户信息
        User user = userService.getCurrentUser(token);

        // 转换为VO返回
        UserVO userVO = convertToUserVO(user);
        userVO.setToken(token);

        return CommonResponse.buildSuccess("注册成功", userVO);
    }

    @PostMapping("/login")
    @ApiOperation("用户登录")
    public CommonResponse<UserVO> login(@RequestBody @Valid LoginReqVO loginReq,
                                        HttpServletResponse response) {

        // 调用登录服务
        String token = userService.login(loginReq.getUsername(), loginReq.getPassword());

        // 设置Cookie
        setCookie(response, token);

        // 获取用户信息
        User user = userService.getCurrentUser(token);

        // 转换为VO返回
        UserVO userVO = convertToUserVO(user);
        userVO.setToken(token);

        return CommonResponse.buildSuccess("登录成功", userVO);
    }

    @PostMapping("/logout")
    @ApiOperation("用户登出")
    public CommonResponse<Boolean> logout(HttpServletRequest request,
                                          HttpServletResponse response) {
        // 获取Token
        String token = getTokenFromCookie(request);

        // 调用登出服务
        if (token != null) {
            userService.logout(token);
        }

        // 清除Cookie
        clearCookie(response);

        return CommonResponse.buildSuccess("登出成功", true);
    }

    @GetMapping("/info")
    @LoginRequired
    @ApiOperation("获取当前用户信息")
    public CommonResponse<UserVO> getUserInfo(HttpServletRequest request) {
        // 获取Token
        String token = getTokenFromCookie(request);

        // 获取用户信息
        User user = userService.getCurrentUser(token);

        // 转换为VO返回
        UserVO userVO = convertToUserVO(user);

        return CommonResponse.buildSuccess(userVO);
    }

    @PutMapping("/update")
    @LoginRequired
    @ApiOperation("更新用户信息")
    public CommonResponse<UserVO> updateUserInfo(@RequestBody UserVO userVO,
                                                 HttpServletRequest request) {
        // 获取Token
        String token = getTokenFromCookie(request);

        // 获取当前用户
        User currentUser = userService.getCurrentUser(token);

        // 设置用户ID
        User user = new User();
        BeanUtils.copyProperties(userVO, user);
        user.setId(currentUser.getId());

        // 调用更新服务
        User updatedUser = userService.updateUserInfo(user);

        // 转换为VO返回
        UserVO updatedUserVO = convertToUserVO(updatedUser);

        return CommonResponse.buildSuccess("更新成功", updatedUserVO);
    }

    @PutMapping("/password")
    @LoginRequired
    @ApiOperation("修改密码")
    public CommonResponse<Boolean> changePassword(@RequestParam @ApiParam("原密码") String oldPassword,
                                                  @RequestParam @ApiParam("新密码") String newPassword,
                                                  @RequestParam @ApiParam("确认密码") String confirmPassword,
                                                  HttpServletRequest request,
                                                  HttpServletResponse response) {
        // 密码一致性校验
        CheckUtil.Biz.INSTANCE.isTrue(
                Objects.equals(newPassword, confirmPassword),
                "两次输入的密码不一致"
        );

        // 获取Token
        String token = getTokenFromCookie(request);

        // 获取当前用户
        User currentUser = userService.getCurrentUser(token);

        // 调用修改密码服务
        boolean result = userService.changePassword(currentUser.getId(), oldPassword, newPassword);

        // 清除Cookie，重新登录
        clearCookie(response);

        return CommonResponse.buildSuccess("密码修改成功，请重新登录", result);
    }

    @GetMapping("/send-code")
    @ApiOperation("发送验证码")
    public CommonResponse<Boolean> sendVerificationCode(@RequestParam @ApiParam("手机号") String phone) {
        // 调用发送验证码服务
        userService.sendVerificationCode(phone);

        return CommonResponse.buildSuccess("验证码已发送", true);
    }

    @PostMapping("/reset-password")
    @ApiOperation("重置密码")
    public CommonResponse<Boolean> resetPassword(@RequestParam @ApiParam("手机号") String phone,
                                                 @RequestParam @ApiParam("验证码") String validCode,
                                                 @RequestParam @ApiParam("新密码") String newPassword,
                                                 @RequestParam @ApiParam("确认密码") String confirmPassword,
                                                 HttpServletResponse response) {
        // 密码一致性校验
        CheckUtil.Biz.INSTANCE.isTrue(
                Objects.equals(newPassword, confirmPassword),
                "两次输入的密码不一致"
        );

        // 调用重置密码服务
        String token = userService.resetPassword(phone, validCode, newPassword);

        // 设置Cookie
        setCookie(response, token);

        return CommonResponse.buildSuccess("密码重置成功", true);
    }

    /**
     * 转换为用户视图对象
     *
     * @param user 用户实体
     * @return 用户视图对象
     */
    private UserVO convertToUserVO(User user) {
        if (user == null) {
            return null;
        }

        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(user, userVO);

        return userVO;
    }

    /**
     * 从Cookie中获取Token
     *
     * @param request HTTP请求
     * @return Token
     */
    private String getTokenFromCookie(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (CommonConstants.COOKIE_NAME.equals(cookie.getName())) {
                    return cookie.getValue();
                }
            }
        }

        return null;
    }

    /**
     * 设置Cookie
     *
     * @param response HTTP响应
     * @param token    Token
     */
    private void setCookie(HttpServletResponse response, String token) {
        Cookie cookie = new Cookie(CommonConstants.COOKIE_NAME, token);
        cookie.setPath("/");
        cookie.setHttpOnly(true);
        cookie.setMaxAge(CommonConstants.TOKEN_EXPIRE_SECONDS);
        response.addCookie(cookie);
    }

    /**
     * 清除Cookie
     *
     * @param response HTTP响应
     */
    private void clearCookie(HttpServletResponse response) {
        Cookie cookie = new Cookie(CommonConstants.COOKIE_NAME, null);
        cookie.setPath("/");
        cookie.setHttpOnly(true);
        cookie.setMaxAge(0);
        response.addCookie(cookie);
    }
}
